package com.hy.security.filter;

import com.alibaba.fastjson.JSONObject;
import com.hy.common.base.RespResult;
import com.hy.common.base.RespResultCode;

import com.hy.common.consts.CommonConst;
import com.hy.common.consts.RedisConst;
import com.hy.common.log.dto.SysOpLogReqDTO;
import com.hy.common.log.eventbus.EventBusFactory;
import com.hy.common.log.eventbus.SysOpLogEvent;
import com.hy.common.log.eventbus.SysOpLogEventBusListener;

import com.hy.common.utils.IPUtil;
import com.hy.security.entity.SecurityUser;
import com.hy.security.security.TokenHandler;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;


import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

/**
 * 登录认证
 */
public class TokenAuthenticationFilter extends UsernamePasswordAuthenticationFilter {


    private AuthenticationManager authenticationManager;
    private TokenHandler tokenHandler;
    private RedisTemplate redisTemplate;

    public TokenAuthenticationFilter(AuthenticationManager authenticationManager,TokenHandler tokenHandler,RedisTemplate redisTemplate) {
        this.authenticationManager = authenticationManager;
        this.tokenHandler = tokenHandler;
        this.redisTemplate = redisTemplate;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/sys/login","POST"));


    }

    //获取客户端提交用户名和密码
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {



        //获取表单提交数据
           String username = request.getParameter("username");
           String password = request.getParameter("password");
            System.out.println(username);
            System.out.println(password);
            ArrayList arrayList=new ArrayList();

            UsernamePasswordAuthenticationToken authRequest=new UsernamePasswordAuthenticationToken(username,password,arrayList);
            this.setDetails(request, authRequest);
           return authenticationManager.authenticate(authRequest);
    }
    //认证成功调用的方法
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //认证成功，得到认证成功之后用户信息
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Expose-Headers","Authorization");
        SecurityUser user = (SecurityUser)authResult.getPrincipal();
        user.getCurrentUserInfo().setPassword("******");
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authResult);
        //根据用户名生成token
        String token = tokenHandler.createToken(user.getCurrentUserInfo().getUserId().toString());
        user.getCurrentUserInfo().setAuthorization(token);


        //把用户名称和用户权限列表放到redis
        redisTemplate.opsForValue().set(RedisConst.PERMISSION_INFO+user.getCurrentUserInfo().getUserId().toString(),user.getRolesValueList());
        redisTemplate.opsForValue().set(RedisConst.USER_INFO+user.getCurrentUserInfo().getUserId().toString(),user.getCurrentUserInfo());
        response.setContentType("application/json;charset=utf-8");

        RespResult result=RespResult.success(user.getCurrentUserInfo()).setCode(200).setMessage("登陆成功！");


        response.getWriter().write(JSONObject.toJSONString(result));
        SysOpLogReqDTO sysOpLogReqDTO=new SysOpLogReqDTO();
        sysOpLogReqDTO.setMenuName("登录");
        sysOpLogReqDTO.setMenuBtn("登录系统");
        sysOpLogReqDTO.setUrl(request.getRequestURI());
        sysOpLogReqDTO.setClassName("DefaultLogin");
        sysOpLogReqDTO.setMethodName("Login");
        sysOpLogReqDTO.setReqType("POST");
        sysOpLogReqDTO.setParams("无");
        sysOpLogReqDTO.setSuccess(true);
        sysOpLogReqDTO.setResult("登录成功！");
        sysOpLogReqDTO.setOpTime(new Date());
        sysOpLogReqDTO.setOpAccount(user.getCurrentUserInfo().getPhone()+"("+user.getCurrentUserInfo().getUsername()+")");
        sysOpLogReqDTO.setOpContent("登录成功！！");
        sysOpLogReqDTO.setOpIp(IPUtil.getIpAddress(request));
        // 发布异步事件
        EventBusFactory.build().registerAsyncEvent(SysOpLogEventBusListener.class);
        EventBusFactory.build().postAsyncEvent(SysOpLogEvent.builder()
                .sysOpLogReqDTO(sysOpLogReqDTO).eventName("后台操作日志发布事件").build());
        //响应头返回token
        response.setHeader("Authorization",token);
        response.getWriter().flush();
        response.getWriter().close();
    }
    //认证失败调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setContentType("application/json;charset=utf-8");

        RespResult result = null;
        if (failed instanceof InternalAuthenticationServiceException){
                result=RespResult.put(RespResultCode.NO_USERNAME);
        }else {
            result=RespResult.put(RespResultCode.NO_AUTHENTICATION);
        }
        response.getWriter().write(JSONObject.toJSONString(result));
        response.getWriter().flush();
        response.getWriter().close();
    }
}
